package com.flowable.converter;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * xml转换器
 */
@Component
public class XmlConverter {

    @Autowired
    private RepositoryService repositoryService;

    /**
     * 存放collection标签对应的值
     * key: userTaskId
     * value: 该userTaskId标签对应collection值
     */
    Map<String, String> collectionMap = new HashMap<>();

    /**
     * 一般是初始化collectionMap，用饿汉式单例
     * 获得collectionMap
     *
     * @param processDefinitionId
     * @return
     */
    public Map<String, String> getCollectionMap(String processDefinitionId) {
        parseXML(processDefinitionId);
        return collectionMap;
    }

    /**
     * 一般是使用collectionMap，用懒汉式单例
     * 根据userTaskId获得collectionMap中对应的值
     *
     * @param processDefinitionId
     * @param userTaskId
     * @return
     */
    public String getCollectionMap(String processDefinitionId, String userTaskId) {
        if (CollectionUtils.isEmpty(collectionMap)) {
            parseXML(processDefinitionId);
        }
        return collectionMap.get(userTaskId);
    }

    /**
     * 解析xml，获得所有userTaskId对应处理人的el表达式
     *
     * @param processDefinitionId
     * @return
     */
    private void parseXML(String processDefinitionId) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
                    processDefinitionId(processDefinitionId)
                    .singleResult();
            String resourceName = processDefinition.getResourceName();
            InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);

            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(inputStream);
            Element root = document.getRootElement();
            Iterator<?> it = root.elementIterator();
            while (it.hasNext()) {
                Element element = (Element) it.next();
                Iterator<?> eleIt = element.elementIterator();
                while (eleIt.hasNext()) {
                    Element e = (Element) eleIt.next();
                    if (e.getName().equalsIgnoreCase("userTask")) {
                        List<Attribute> attributes = e.attributes();
                        attributes.forEach(attribute -> {
                            // userTask标签对应id
                            if (attribute.getName().equalsIgnoreCase("id")) {
                                Iterator mulIt = e.elementIterator();
                                while (mulIt.hasNext()) {
                                    Element mule = (Element) mulIt.next();
                                    if (mule.getName().equalsIgnoreCase("multiInstanceLoopCharacteristics")) {
                                        List<Attribute> as = mule.attributes();
                                        as.forEach(a -> {
                                            if (a.getName().equalsIgnoreCase("collection")) {
                                                collectionMap.put(attribute.getValue(), getElKey(a.getValue()));
                                            }
                                        });
                                    }
                                }
                            }
                        });
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("读取xml文件失败： " + e.getMessage());
        }
    }

    /**
     * 根据正则表达式，得到el表达式的key
     */
    private String getElKey(String el) {
        Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
        Matcher matcher = pattern.matcher(el);
        String key = "";
        if (matcher.find()) {
            key = matcher.group(1); // 这将提取出node
        }
        return key;
    }
}
